package cn.icare.cms.controller;

import ch.qos.logback.core.joran.spi.XMLUtil;
import cn.icare.cms.*;
import cn.icare.cms.config.FeigeConfig;
import cn.icare.cms.config.WxInfoConfig;
import cn.icare.cms.dao.po.Order;
import cn.icare.cms.model.enums.OrderStatusEnum;
import cn.icare.cms.model.enums.PayTypeEnum;
import cn.icare.cms.model.feige.ro.FeigeMessageInfo;
import cn.icare.cms.model.feige.ro.MessageData;
import cn.icare.cms.model.feige.ro.MessageItem;
import cn.icare.cms.model.wx.vo.WxBaseResponse;
import cn.icare.cms.model.wx.vo.WxPayNotifyVo;
import cn.icare.cms.model.wx.vo.WxRefundNotifyVo;
import cn.icare.cms.model.wx.vo.WxReqInfo;
import cn.icare.cms.sync.SyncOrderService;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONObject;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.CrossOrigin;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.ByteArrayOutputStream;
import java.io.InputStream;
import java.math.BigDecimal;
import java.util.Date;
import java.util.Map;

@CrossOrigin
@RestController
@RequestMapping(value = "/rest/notify")
@Api(tags = "REST回调接口类")
public class BaseNotifyController extends BaseController {

    @Autowired
    private OrderService orderService;

    @Autowired
    private WxInfoConfig wxInfoConfig;

    @Autowired
    private SyncOrderService syncOrderService;

    @Autowired
    private FeigeConfig feigeConfig;

    private final Logger logger = LoggerFactory.getLogger(BaseNotifyController.class);

    /**
     * <p>回调Api</p>
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @PostMapping(value = "wxPayNotify")
    @ApiOperation(value = "微信支付回调接口")
    public void wxPayNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        InputStream inputStream = request.getInputStream();
        //获取请求输入流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.close();
        inputStream.close();
        String content = new String(outputStream.toByteArray(), "utf-8");
        this.logger.info("wxPayNotify data：" + content);

        WxPayNotifyVo wxPayNotifyVo = (WxPayNotifyVo) XmlUtil.deserialize(content, WxPayNotifyVo.class);
        //Map<String, Object> map = (Map<String, Object>) XmlUtil.deserialize(new String(outputStream.toByteArray(), "utf-8"), Map.class);

        logger.info("【小程序支付回调】 回调数据： \n" + JSON.toJSONString(wxPayNotifyVo));

        String resXml = "";

        if (wxPayNotifyVo != null) {
            String returnCode = wxPayNotifyVo.getReturn_code();
            if ("SUCCESS".equalsIgnoreCase(returnCode)) {
                String returnmsg = wxPayNotifyVo.getResult_code();
                if ("SUCCESS".equals(returnmsg)) {
                    //更新数据
                    boolean result = false;
                    String idStr = wxPayNotifyVo.getAttach();//订单Id
                    String orderCode = wxPayNotifyVo.getOut_trade_no();//订单号
                    Long id = Long.valueOf(idStr);
                    String total_fee = wxPayNotifyVo.getTotal_fee(); //订单金额分
                    BigDecimal total_feeB = new BigDecimal(total_fee).divide(new BigDecimal(100));
                    Order order = orderService.getOne(id);
                    if (order != null && orderCode.equals(order.getCode())
                            && total_feeB.compareTo(order.getAmmount()) == 0 &&
                            order.getStatus() == 0
                    ) {
                        result = this.orderService.updatePayFinished(id, PayTypeEnum.WxPay);
                        //订单支付成功后，需要删除订单支付过程记录
                        syncOrderService.removeOrderPayingLog(id);
                        //新订单微信通知给系统管理员
                        sendNewOrderMessage(order);

                    } else {
                        this.logger.warn("数据库订单数据:" + JSONObject.toJSONString(order));
                        this.logger.warn(String.format("订单Id:%s,订单编号:%s,订单金额:%s 与系统中的订单数据不符", id, orderCode, total_feeB));
                        result = true;
                    }
                    if (result) {
                        //支付成功
                        resXml = "<xml>" + "<return_code><![CDATA[SUCCESS]]></return_code>"
                                + "<return_msg><![CDATA[OK]]></return_msg>" + "</xml>";
                    }
                } else {
                    resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                            + "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
                    logger.info("支付失败:" + resXml);
                }
            } else {
                resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                        + "<return_msg><![CDATA[报文为空]></return_msg>" + "</xml>";
                logger.info("【订单支付失败】");
            }
        } else {
            resXml = "<xml>" + "<return_code><![CDATA[FAIL]]></return_code>"
                    + "<return_msg><![CDATA[XML数据解析失败]></return_msg>" + "</xml>";
        }

        logger.info("【小程序支付回调响应】 响应内容：\n" + resXml);
        response.getWriter().print(resXml);
    }


    /**
     * <p>回调Api</p>
     *
     * @param request
     * @param response
     * @throws Exception
     */
    @PostMapping(value = "wxRefundNotify")
    @ApiOperation(value = "微信退款回调接口")
    public void wxRefundNotify(HttpServletRequest request, HttpServletResponse response) throws Exception {
        InputStream inputStream = request.getInputStream();
        //获取请求输入流
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        byte[] buffer = new byte[1024];
        int len = 0;
        while ((len = inputStream.read(buffer)) != -1) {
            outputStream.write(buffer, 0, len);
        }
        outputStream.close();
        inputStream.close();
        String content = new String(outputStream.toByteArray(), "utf-8");
        this.logger.info("wxRefundNotify data：" + content);

        WxRefundNotifyVo wxPayNotifyVo = (WxRefundNotifyVo) XmlUtil.deserialize(content, WxRefundNotifyVo.class);

        logger.info("【小程序退款回调】 回调数据： \n" + JSON.toJSONString(wxPayNotifyVo));

        String resXml = "";
        WxBaseResponse wxBaseResponse = new WxBaseResponse();
        wxBaseResponse.setReturn_code("FAIL");
        if (wxPayNotifyVo != null) {
            String returnCode = wxPayNotifyVo.getReturn_code();
            if ("SUCCESS".equalsIgnoreCase(returnCode)) {

                String reqInfo = wxPayNotifyVo.getReq_info(); //这是加密码的信息，需要解密
                this.logger.debug("req_info:" + reqInfo);
                //1-密钥生成，规则 =MD5(商户支付密钥).toLowerCase()
                String lowMD5Key = MD5Util.MD5Encode(wxInfoConfig.getMch_key(), "UTF-8").toLowerCase();
                AESUtil aesUtil = new AESUtil();
                String decodeData = aesUtil.decrypt(reqInfo, lowMD5Key);
                this.logger.debug("decodeData:" + decodeData);
                if (StringUtil.isNotEmpty(decodeData)) {
                    WxReqInfo wxReqInfo = (WxReqInfo) XmlUtil.deserialize(decodeData, WxReqInfo.class);
                    if (wxReqInfo != null && "SUCCESS".equals(wxReqInfo.getRefund_status())) {
                        String orderCode = wxReqInfo.getOut_trade_no();
                        Order order = this.orderService.getOneByCode(orderCode);
                        if (order != null) {
                            //1-更新订单状态
                            this.orderService.updateStatus(order.getId(), OrderStatusEnum.CANCEL.getCode());
                            //2-恢复商品库存量
                            this.resumeOrderItemStore(order.getId());
                            wxBaseResponse.setReturn_code("SUCCESS");//退款成功
                        } else {
                            this.logger.warn("编号:% 的订单不存在", orderCode);
                        }
                    } else {
                        this.logger.error("WxReqInfo:返序列化失败");
                    }

                } else {

                    wxBaseResponse.setReturn_msg("req_info数据解密失败");
                }

            }
        } else {
            wxBaseResponse.setReturn_msg("XML数据解析失败");
        }
        resXml = XmlUtil.serializer(wxBaseResponse);
        logger.info("【小程序申请退款回调响应】 响应内容：\n" + resXml);
        response.getWriter().print(resXml);
    }


    public static void main(String[] args) {

        String total_fee = "100"; //订单金额分
        BigDecimal total_feeB = new BigDecimal(total_fee).divide(new BigDecimal(100));
        String id = "90";
        String orderCode = "12020051216423871249528450636121";
        Order order = new Order();
        order.setAmmount(new BigDecimal("1.00"));
        order.setCode("12020051216423871249528450636121");
        order.setStatus(0);
        if (order != null && orderCode.equals(order.getCode())
                && total_feeB.compareTo(order.getAmmount()) == 0 &&
                order.getStatus() == 0
        ) {
            System.out.println("支付成功");
            //
        } else {
            System.out.println("数据库订单数据:" + JSONObject.toJSONString(order));
            System.out.println(String.format("订单Id:%s,订单编号:%s,订单金额:%s 与系统中的订单数据不符", id, orderCode, total_feeB));

        }
    }

    private void sendNewOrderMessage(Order order) {
        FeigeMessageInfo feigeMessageInfo = new FeigeMessageInfo();
        feigeMessageInfo.setApp_key(feigeConfig.getApp_key());
        feigeMessageInfo.setSecret(feigeConfig.getSecret());
        feigeMessageInfo.setTemplate_id(feigeConfig.getTemplate_id());
        feigeMessageInfo.setUrl("http://web.yilugb.com");
        MessageData messageData = new MessageData();
        messageData.setFirst(new MessageItem("待处理订单", "##000000"));
        messageData.setKeyword1(new MessageItem("您有新订单，请及时配送", "#FF6600"));
        messageData.setKeyword2(new MessageItem("逛呗运营组", "#000000"));
        messageData.setKeyword3(new MessageItem(DateUtil.formateToDateTime(new Date(), "yyyy-MM-dd HH:mm:ss"), "#000000"));
        messageData.setRemark(new MessageItem("逛呗订单中心", "#000000"));
        feigeMessageInfo.setData(messageData);
        syncOrderService.sendMessage(feigeConfig.getApiUrl(), feigeMessageInfo, order);
    }
}
